package com.authine.cloudpivot.ext.controller;


import cn.hutool.core.date.DateUnit;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.engine.api.model.organization.UserModel;
import com.authine.cloudpivot.engine.api.model.runtime.*;
import com.authine.cloudpivot.engine.component.query.api.FilterExpression;
import com.authine.cloudpivot.engine.component.query.api.Page;
import com.authine.cloudpivot.engine.component.query.api.helper.PageableImpl;
import com.authine.cloudpivot.engine.component.query.api.helper.Q;
import com.authine.cloudpivot.engine.enums.status.SequenceStatus;
import com.authine.cloudpivot.engine.enums.status.WorkflowInstanceStatus;
import com.authine.cloudpivot.engine.enums.type.DefaultPropertyType;
import com.authine.cloudpivot.engine.enums.type.UnitType;
import com.authine.cloudpivot.ext.vo.assetcmdb2nc.AssetDictionary;
import com.authine.cloudpivot.web.api.controller.base.BaseController;
import com.authine.cloudpivot.web.api.utils.HttpClientUtils;
import com.authine.cloudpivot.web.api.view.ResponseResult;
import com.authine.cloudpivot.web.api.view.runtime.StartWorkflowDataVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@RequestMapping("/api/asset")
@RestController
@Slf4j
@SuppressWarnings("unchecked")
public class AssetManagementController extends BaseController {

    @Value("${asset.cmdb.Host:http://cmdb.test.wz-inc.com}")
    private  String cmdbHost;

    @Value("${asset.cmdb.LogListUrl:/api/v1/commits}")
    private  String cmdbLogListUrl;
    @Value("${asset.cmdb.LogRecord:/api/v1/commits}")
    private String cmdbLogRecord;
    @Value("${asset.cmdb.cmdbBaseDeviceInfo:/api/v1/cts/BasestationDevice/cis?assetno=}")
    private String cmdbBaseDeviceInfo;
    @Value("${asset.ncSync.ncFaCardServlet:http://172.16.225.39:8090/service/FaCardServlet}")
    private String ncFaCardServlet;
    @Value("${asset.itsm.orderUrl:http://itsm-dev.wz-inc.com/itsm/api/1.0/order_trace.json}")
    private String itsmOrderUrl;
    @Value("${asset.cmdb.assetAdminId:40287811739dc24301739ea704ac0126}")
    private String assetAdminId;
    @Value("${asset.cmdb.approvalUser:v-shu.yun}")
    private String approvalUserCode;

    /**
     * 审批后的数据 需要同步至 nc 的池
     */
    private final String cmdb_asset_nc_sync ="cmdb_asset_nc_sync";
    /**
     * 资产明细
     */
    private final String asset_info ="asset_info";

    @Autowired
    private CustmStartWorkflow custmStartWorkflow;

    ExecutorService executorService = Executors.newSingleThreadExecutor();

    @Autowired
    RedisTemplate redisTemplate;

    static   AssetDictionary filterConditions = new AssetDictionary();

    /**
     *  获取过滤条件，该缓存数据只在某一段时间的循环体里使用
     *  使用成员变量缓存
     */
    private void getFilterCondition(){

        String key ="assetFilterCondition";

        //redis 里的缓存标识是否存在
        Boolean sfc = redisTemplate.hasKey(key);
        //存在，直接返回，
        if (sfc != null && sfc){
            //判断缓存标识存在时间是否小于55 分钟，尝试刷新缓存
            Long minute = redisTemplate.getExpire(key,TimeUnit.MINUTES);

            if (filterConditions.isFail() && (  minute ==null ||  minute<55)){
                filterConditions.setRefresh(true);
            }
        }else{
            //不存在尝试刷新缓存
            filterConditions.setRefresh(true);
        }

        //缓存需要刷新
        if (filterConditions.isRefresh()){
            log.info("获取字典数据");
            filterConditions = assetDictionary();

            if (filterConditions.isFail()){
                log.info("获取 nc同步条件配置数据失败");
            }else{
                log.info("获取 nc同步数据条件成功");
            }

            redisTemplate.opsForValue().set(key,filterConditions,1, TimeUnit.HOURS);
        }else{
            Object o = redisTemplate.opsForValue().get(key);
            if (o != null){
                filterConditions = (AssetDictionary)o;
            }
        }

    }

    /**
     *  字典配置信息， 获取属性配置和状态配置信息
     * @return
     */
    private AssetDictionary assetDictionary(){
        AssetDictionary assetDictionary = new AssetDictionary();

        List<String> assetSection = assetCMDBtoNCType();

        if (assetSection.isEmpty() ){
            log.info("获取 nc同步数据条件，资产小类数据未配置");
//            return assetDictionary;
        }


        String schemaCode = "asset_dictionary";
        BizObjectQueryModel queryModel = new BizObjectQueryModel();
        queryModel.setFilterExpr(Q.it("asset_dict_status", FilterExpression.Op.Eq,"Y"));
        queryModel.setSchemaCode(schemaCode);
        queryModel.setQueryCode(schemaCode);
        queryModel.setPageable(new PageableImpl(0,Integer.MAX_VALUE));
        Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);
        // 获取ys2nc属性配置信息
        Map<String, Map<String, String>> attributeMapping = bizObjectModelPage.getContent().stream()
                .filter(a -> "asset_cmdb_attribute".equals(a.getString("asset_dict_info")) && "Y".equals(a.getString("asset_dict_ys2nc")))
                .collect(Collectors.toMap(
                        a -> a.getString(AssetDictionary.assetDictKey), a -> MapUtil.builder(AssetDictionary.toNc, a.getString(AssetDictionary.toNc))
                                .put(AssetDictionary.toYs,a.getString( AssetDictionary.toYs)).put(AssetDictionary.assetDictValue,a.getString(AssetDictionary.assetDictValue))
                                .put(AssetDictionary.assetDictKey,a.getString(AssetDictionary.assetDictKey))

                                .build(),
                        (k1, k2) -> k1
                ));

        if (attributeMapping.isEmpty()) {
            log.info("获取 nc同步数据条件，属性配置未获取数据");
//            return assetDictionary;
        }

        //获取状态配置信息
        List<String> statusList = bizObjectModelPage.getContent().stream()
                .filter(a -> "asset_y2nc_status".equals(a.get("asset_dict_info")) && "Y".equals(a.getString("asset_dict_ys2nc")))
                .map(a -> (String) a.get("asset_dict_value")).collect(Collectors.toList());

        if (statusList.isEmpty()) {
            log.info("获取 nc同步数据条件，状态配置未获取配置数据");
//            return assetDictionary;
        }


        //获取国家配置信息
        List<String> countryList = bizObjectModelPage.getContent().stream()
                .filter(a -> "asset_y2nc_country".equals(a.get("asset_dict_info")) && "Y".equals(a.getString("asset_dict_ys2nc")))
                .map(a -> (String) a.get("asset_dict_value")).collect(Collectors.toList());

        if (countryList.isEmpty()) {
            log.info("获取 nc同步数据条件，国家未获取得配置");
        }

        //设备归属
        List<String> deviceOwnerList = bizObjectModelPage.getContent().stream()
                .filter(a -> "asset_y2nc_ownership".equals(a.get("asset_dict_info"))  && "Y".equals(a.getString("asset_dict_ys2nc")))
                .map(a -> (String) a.get("asset_dict_value")).collect(Collectors.toList());

        if (deviceOwnerList.isEmpty()) {
            log.info("获取 nc同步数据条件，设备归属未获取得配置");
        }

        //部门配置
        Map<String, String> assetCmdb2ysDept = bizObjectModelPage.getContent().stream().filter(a -> "asset_cmdb2ys_dept".equals(a.getString("asset_dict_info")))
                .collect(Collectors.toMap(a -> a.getString("cmdb2ys"), a -> a.getString("asset_dict_key")));
        if (assetCmdb2ysDept.isEmpty()) {
            log.info("获取资产明细部门配置数据配置，未获取得配置");
        }

        assetDictionary.setAssetSection(assetSection);
        assetDictionary.setAttributeMapping(attributeMapping);
        assetDictionary.setAttributeList(new ArrayList<>(attributeMapping.keySet()));
        assetDictionary.setStatusList(statusList);
        assetDictionary.setCountryList(countryList);
        assetDictionary.setDeviceOwnerList(deviceOwnerList);
        assetDictionary.setAssetCmdb2ysDept(assetCmdb2ysDept);


        //获取数据成功
        assetDictionary.setFail(false);

        return  assetDictionary;
    }

    /**
     *  资产同步nc 数据 ,获取资产小类 asset_division
     * @return
     */
    private List<String> assetCMDBtoNCType(){
        String schemaCode = "asset_CMDBtoNC_type";
        BizObjectQueryModel queryModel = new BizObjectQueryModel();
        queryModel.setFilterExpr(Q.it("asset_cmdb2nc_status", FilterExpression.Op.Eq,"是"));
        queryModel.setSchemaCode(schemaCode);
        queryModel.setQueryCode(schemaCode);
        queryModel.setPageable(new PageableImpl(0,Integer.MAX_VALUE));

        Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);

        return bizObjectModelPage.getContent().stream().map(a -> (String) a.get("asset_division")).collect(Collectors.toList());
    }

    /**
     *  查询biz数据是否已存在
     * @param schemaCode
     * @param val
     * @return
     */
    private boolean existsBizByParm(String schemaCode, Object val){
        BizObjectQueryModel queryModel = new BizObjectQueryModel();
        queryModel.setFilterExpr(Q.it("commit_id", FilterExpression.Op.Eq,val));
        queryModel.setSchemaCode(schemaCode);
        queryModel.setQueryCode(schemaCode);
        queryModel.setPageable(new PageableImpl(0,1));

        Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);

        return bizObjectModelPage.getTotal() != 0;

    }

    /**
     * 获取cmdb 日志列表， 默认获取前一天的
     * @param startTime
     * @param endTime
     * @return
     */
    @RequestMapping("getCmdbRecordList")
    public ResponseResult<Object> getCmdbRecordList(Long startTime, Long endTime){
        ResponseResult.ResponseResultBuilder<Object> rst = ResponseResult.builder();

        if (startTime == null) {

            long daymillis = DateUnit.DAY.getMillis();
            endTime=System.currentTimeMillis()/daymillis*daymillis-TimeZone.getDefault().getRawOffset()-1;//昨天23：59：59 毫秒数
            startTime = endTime -daymillis+1;//昨天凌晨毫秒数

        }

        String url = cmdbHost.concat(cmdbLogListUrl).concat("?startTime=").concat(String.valueOf(startTime)).concat("&endTime=").concat(String.valueOf(endTime));

        String respStr = HttpClientUtils.doGet(url,1000,5000,120000);
        log.info("respStr={},url={}",respStr,url);
        if (StringUtils.isEmpty(respStr)){
            return rst.errcode(-1L).errmsg("失败").build();
        }

        JSONObject respObj = (JSONObject) JSONObject.parse(respStr);

        List<Map<String,Object>> jsonArray = respObj.getObject("data", ArrayList.class);

        log.info("jsonArray={}",jsonArray);

        if (jsonArray == null || jsonArray.size()==0) {
            return rst.errcode(0L).errmsg("无数据").build();
        }
        final  String status = "confirmed";
        final List<String> commitids = jsonArray.stream().filter(a -> status.equals(a.get("status"))).map(a -> Optional.of(a.get("id")).orElse("").toString()).collect(Collectors.toList());

        getCmdbAssetChangeRecordDetail(commitids);



        return rst.errcode(0L).errmsg("成功").build();
    }


    /**
     *  获取cmdb 日志详情并做相关逻辑
     *
     */
    @RequestMapping("getCmdbAssetChangeRecordDetail")
    public ResponseResult<Object> getCmdbAssetChangeRecordDetail(List<String> commitids ){

        List<String> fialList = new ArrayList<>();

        commitids.forEach(a->{

            ResponseResult<Object> responseResult = this.lunchRecordWorkflow(a);

            if (responseResult.getErrcode()!=0){
                fialList.add(a.concat("-->").concat(responseResult.getErrmsg()));
            }

        });


        if (!fialList.isEmpty()){
            log.info("同步失败{}条数据：{}",fialList.size(),fialList);
            return ResponseResult.builder().errcode(0L).errmsg("有失败的commitId").data(MapUtil.builder("fialList",fialList).build()).build();
        }

        return ResponseResult.builder().errcode(0L).errmsg("成功").build();

    }


    /**
     *  根据 cmdb commitId 获保存cmdb 记录和发起流程审批
     * @param commit_id
     * @return
     */
    @RequestMapping("lunchRecordWorkflow")
    public ResponseResult<Object> lunchRecordWorkflow(String commit_id){
        ResponseResult.ResponseResultBuilder<Object> rstBuilder = ResponseResult.builder();
        try {


            String cmdb_asset_change_record = "cmdb_asset_change_record";

            //去重校验
            boolean existRecord = existsBizByParm(cmdb_asset_change_record, commit_id);
            //cmdb里清理过的，需要审批记录的流程
            String cmdb_asset_approval = "cmdb_asset_approval";
            boolean existApproval = existsBizByParm(cmdb_asset_approval, commit_id);

            if (existRecord && existApproval){
                return rstBuilder.errmsg(String.format("commit_id =%s 的日志和审批都已存在",commit_id ) ).errcode(-1L).build();
            }


            // 1.根据 commit_id 从cmdb 获取 信息
            String url = cmdbHost.concat(cmdbLogRecord).concat("/").concat(commit_id);

            log.info("获取cmdb 消息详情 url = {}",url);
            String rst = HttpClientUtils.doGet(url,1000,5000,15000);

            if (StringUtils.isEmpty(rst)) {
                log.info("cmdb 获取信息数据为空,url = {}",url);
                return rstBuilder.errcode(-1L).errmsg("cmdb 获取信息数据为空").build();
            }

            if (log.isDebugEnabled()) {
                log.debug("返回数据rst={}",rst);
            }

            // 2. 解析数据并组装数据
            JSONObject parse = (JSONObject) JSON.parse(rst);

            if (log.isDebugEnabled()) {
                log.debug("rst 解析数据 parse={}",parse);
            }

            JSONObject data = parse.getJSONObject("data");

            List<Map<String,Object>> jsonArray = (List<Map<String, Object>>) data.get("alter_records");


            // cmdb 资产变更日志表 基础信息
            Map<String, Object> alterRecordsParam = MapUtil.builder(new HashMap<String,Object>(16))
                    .put("from_sys",data.getString("from_sys"))
                    .put("from_sys_ref",data.getString("from_sys_ref"))
                    .put("ctime", new Date(data.getLong("ctime")))
                    .put("creator",data.getString("creator"))
                    .put("commit_id",data.get("id"))
                    .put("data_status",data.getString("status"))
                    .put("mtime",new Date(data.getLong("mtime")))
                    .build();
            //cmdb 资产变更审批流程表单 基础信息
            Map<String, Object> approvalParam = MapUtil.builder(new HashMap<String, Object>(16)).putAll(alterRecordsParam).build();

            //cmdb 资产变更日志表 明细信息
            List<Map<String, Object>> mapList = new ArrayList<>();
            alterRecordsParam.put("cmdb_alter_records",mapList);

            //cmdb 资产变更日志表 明细信息
            List<Map<String, Object>> approvalParamList = new ArrayList<>();

            //加载条件
            getFilterCondition();

            for (Map<String, Object> map : jsonArray) {
                Map<String, Object> tempMap = MapUtil.builder(new HashMap<String, Object>(16))
                        .put("record_id", map.get("id"))
                        .put("alter_type", map.get("alter_type"))
                        .put("ci_id", map.get("ci_id"))
                        .put("ci_type_id", map.get("ci_type_id"))
                        .put("ci_type_name", map.get("ci_type_name"))
                        .put("source_display_name", map.get("source_display_name"))
                        .put("attr_id", map.get("attr_id"))
                        .put("attr_name", map.get("attr_name"))
                        .put("old_val", map.get("old_val"))
                        .put("new_val", map.get("new_val"))
                        .build();
                if (!existRecord) {
                    mapList.add(tempMap);
                }

                //匹配出需要审批的数据,modify_attr_val ,create_attr_val
                if (!existApproval && StringUtils.equalsAny((String)map.get("alter_type"),"modify_attr_val","create_attr_val")
                        && filterConditions.getAttributeList().contains(String.valueOf(tempMap.get("attr_id")))) {
                    approvalParamList.add(tempMap);
                }

            }

            log.info("组装后的数据完成");


            String bizId;

            // 资产变更日志表保存
            if (! existRecord){
                BizObjectModel bizObjectModel = new BizObjectModel(cmdb_asset_change_record, alterRecordsParam, false);
                bizId = getBizObjectFacade().saveBizObject(gainAssetAdminId(), bizObjectModel, true);
                log.info("资产变更日志表保存结果 {}",bizId);
            }

            if (existApproval){
                log.info("资产变更审批流程已存在 ");
            }else {
                //需要审批的资产过滤
                String fromSysRef = (String) approvalParam.get("from_sys_ref");
                 approvalParamList = filterApprovalDevice(fromSysRef, approvalParamList);
                approvalParam.put("approval_alter_records",approvalParamList);
                //资产变更审批流程发起
                if (  approvalParamList.size()>0 ){
                    log.info("approvalParamList={}",approvalParamList.size());
                    StartWorkflowDataVO bizObject = new StartWorkflowDataVO();
                    bizObject.setWorkflowCode(cmdb_asset_approval);
                    bizObject.setUsername(gainApprovalUserCode());
                    bizObject.setFinishStart(true);
                    bizObject.setData(approvalParam);

                    //构建审批流程里的子表透视图
                    approvalParam.put("records_view",recordsView(approvalParamList));

                    ResponseResult<String> responseResult = custmStartWorkflow.startWorkflow(bizObject);
                    log.info("资产变更审批流程发起 {}",responseResult);
                }else{
                    log.info("没有匹配资产变更审批流程数据 ");
                }
            }

        } catch (Exception e) {
            log.info("系统异常:".concat(Optional.ofNullable(e.getMessage()).orElse("...")),e );
            return rstBuilder.errcode(-1L).errmsg("系统异常").build();
        }


        return rstBuilder.errcode(0L).errmsg("成功").build();
    }



    /**
     *  需要审批的资产过滤
     *  国家 是中国
     *  设备归属是 千寻
     *  设备小类 是  配置中的
     *  小类是接收机->接收机  ReceiverType = 整机
     *
     *  是否备件更换流程： 1.是
     *                2.不是  需判断设备状态
     *
     */
    private List<Map<String, Object>>  filterApprovalDevice(String fromSysRef,List<Map<String, Object>> approvalParamList){

        Map<String, List<Map<String, Object>>> groupByMap = approvalParamList.stream().collect(Collectors.groupingBy(a -> (String)a.get("source_display_name")));

        List<Map<String, Object>> rstList = new ArrayList<>();
        Map<String, Boolean> deviceReplace = null;


        for (Map.Entry<String,List<Map<String, Object>>> entry: groupByMap.entrySet()){

            String rst = HttpClientUtils.doGet(cmdbHost.concat(cmdbBaseDeviceInfo.concat(entry.getKey())));
            if (StringUtils.isNotEmpty(rst)){
                JSONObject rstJson = JSON.parseObject(rst);

                if ("1000".equals(rstJson.getString("code"))){
                    JSONArray jsonArray = rstJson.getJSONArray("data");
                    JSONObject data;
                    if (jsonArray != null && jsonArray.size()>0 && (data = jsonArray.getJSONObject(0)) !=null){

                        if (filterConditions.isFail() ){
                            continue ;
                        }
                        // 小类不在配置中的忽略
                        if (  !filterConditions.getAssetSection().contains(data.getString("DeviceType"))){
                            continue;
                        }
                        // 设备形态非整机的忽略
                        if("接收机".equals(data.getString("DeviceType")) && !"整机".equals(data.getString("ReceiverType"))){
                            continue;
                        }

                        //  国家不在配置中的忽略
                        if (!filterConditions.getCountryList().contains(data.getString("Country"))){
                            continue ;
                        }


                        //获取备件更换信息
                        if (deviceReplace  == null) {
                            deviceReplace = isDeviceReplace(fromSysRef,approvalParamList);
                        }
                        //非备件更换做额外的判断
                        if (!deviceReplace.get("isDevice") ){
                            // 设备状态是否 在配置中
                            if(!filterConditions.getStatusList().contains(data.getString("DeviceStatus"))){
                                continue;
                            }
                            //设备归属不在配置中的忽略
                            if (!filterConditions.getDeviceOwnerList().contains(data.getString("DeviceOwner"))){
                                continue;
                            }


                        }
                        rstList.addAll(entry.getValue());
                    }

                }
            }

        }

        //  判断是备件更换及 否是非千寻的 ,再数据组合

        if (deviceReplace != null && deviceReplace.get("isRecombination")){
            rstList = deviceData(rstList);
        }

        // 这里的record_id 是从 cmdb 获取的 ,是 数值类型， 落库云枢会转成 String,所以直接强转
        return rstList.stream().sorted(Comparator.comparing(a-> (Integer)a.get("record_id") )).collect(Collectors.toList());
    }


    private List<Map<String, Object>> deviceData(List<Map<String, Object>> records){
        Map<Object, List<Map<String, Object>>> groupMap = records.stream().collect(Collectors.groupingBy(a -> a.get("source_display_name")));
        if (groupMap.size() !=2){
            log.info("cmdb 资产变更审批流程：数据不匹配设备更换逻辑,groupdMap.size != 2：目前groupMap.size ={}",groupMap.size());
            return records;
        }

        String  newSourceName = (String) records.stream().max(Comparator.comparing(a -> (Integer) a.get("record_id") )).orElse(MapUtil.newHashMap()).get("source_display_name");
        String  oldSourceName =  (String) records.stream().min(Comparator.comparing(a -> (Integer) a.get("record_id") )).orElse(MapUtil.newHashMap()).get("source_display_name");

        if (StringUtils.isEmpty(newSourceName) || StringUtils.isEmpty(oldSourceName) || newSourceName.equals(oldSourceName) ){
            log.info("cmdb 资产变更审批流程：record_id 最大和最小的 资产编码一样或者为空不符合设备变更逻辑，newSourceName ={},oldSourceName={}",newSourceName,oldSourceName);
            return records;
        }

        //资产卡片SS 里 A设备下架，B设备上架，   把B资产提交信息里的新值放到A资产里的新值里
        List<Map<String, Object>> newList = groupMap.get(newSourceName);
        List<Map<String, Object>> oldList = groupMap.get(oldSourceName);

        List<Map<String, Object>> collect = oldList.stream().filter(a ->
                newList.stream().anyMatch(b -> {
                    if (b.get("attr_id").equals(a.get("attr_id")) && !a.get("old_val").equals(b.get("new_val"))) {
                        a.put("new_val", b.get("new_val"));
                        return true;
                    }
                    return false;
                })
        ).collect(Collectors.toList());

        Optional<Map<String, Object>> any = newList.stream().findAny();

        if (any.isPresent()){
            //创建一条数据旧的资产编码修改成新的
            log.info("cmdb 资产变更审批流程：开始构建资产编号更新操作");
            MapBuilder<String, Object> put = MapUtil.builder(any.get()).put("attr_id", "61")
                    .put("attr_name", "资产编号").put("old_val", oldSourceName).put("new_val", newSourceName).put("source_display_name",oldSourceName);
            collect.add(put.build());
            records = collect;

        }else{
            log.info("cmdb 资产变更审批流程：构建资产编号更新操作失败");

        }
        return records;
    }




    /**
     *  判断是否是设备变更的操作和是否千寻的品牌
     *  1.先判断 所有操作是否都是 modify_attr_val 和 操作资产是两个
     *  2. 通过itsm 获流程类型是 备件更换流程
     *  3. 通过cmdb 接口获取资产信息，品牌不是千寻的
     *
     * @return  Map<String,String> isDevice,isRecombination
     */
    private Map<String,Boolean> isDeviceReplace(String fromSysRef, List<Map<String,Object>> records){

        String  rstStr = "";
        MapBuilder<String, Boolean> rstMap = new MapBuilder<String, Boolean>(new HashMap<>()).put("isDevice", false).put("isRecombination", false);

        try {


            rstStr = HttpClientUtils.doPost(itsmOrderUrl, StrUtil.format("{\"orderId\":\"{}\"}", fromSysRef ), null);

            if (StringUtils.isNotEmpty(rstStr)) {
                JSONObject rstJson = JSON.parseObject(rstStr);

                int code = Optional.of(rstJson.getInteger("code")).orElse(0);

                if (code==200){
                    JSONObject data = rstJson.getJSONObject("data");

                    if (data != null ){
                        String display_name = data.getString("display_name");
                        log.info("itsm display_name :{}", display_name);

                        if ("备件更换流程".equals(display_name)) {

                            rstMap.put("isDevice", true);

                            log.info("资产审批,判断通过是备件更换流程");
                            //获取提交详情id 最大的 资产编号去判断 品牌是否是 千寻的
                            String assetnum = (String) records.stream().filter(a-> "modify_attr_val".equals(a.get("alter_type")) ).max(Comparator.comparing(a -> Integer.valueOf(a.get("record_id").toString())))
                                    .orElse(new HashMap<>()).get("source_display_name");
                            String assetRst = HttpClientUtils.doGet(cmdbHost.concat(cmdbBaseDeviceInfo.concat(assetnum)));
                            log.info("资产审批-备件更换,上线资产编号：{}",assetnum);
                            if (StringUtils.isNotEmpty(assetRst)){
                                JSONObject assetJson = JSON.parseObject(assetRst);
                                if ("1000".equals(assetJson.getString("code"))){

                                    JSONArray assetArray = assetJson.getJSONArray("data");
                                    JSONObject assetData;
                                    if (assetArray != null && assetArray.size()>0 && ( assetData = assetArray.getJSONObject(0)) !=null){
                                        //品牌非千寻的需要数据重组
                                        rstMap.put("isRecombination", !"千寻".equals(assetData.getString("Brand")));
                                    }
                                }
                            }
                        }
                    }else{
                        log.info("itsm data is null");
                    }
                }else{
                    log.info("itsm call code is not 200");
                }
            }else{
                log.info("itsm response body is null");
            }

        } catch (Exception e) {
            log.info(StrUtil.format("itsm 请求流程判断异常rstStr= {}, error={}",rstStr,e.getMessage()),e);
            e.printStackTrace();
        }

        return rstMap.build();
    }


    /**
     *  需求方要在流程里搞个透视图

     */
    private List<Map<String, Object>> recordsView(List<Map<String, Object>> approvalParamList){
        final List<Map<String, Object>> list = new ArrayList<>();

//        getFilterCondition();
//
//        List<String> attrkeyList;
//
//        if (filterConditions.isFail()){
//            log.info("获取字段配置的属性失败，使用默认值");
//
//            attrkeyList = Arrays.asList("61","60","58","62","59","2");
//        }else {
//            attrkeyList = filterConditions.getAttributeMapping().keySet().stream().collect(Collectors.toList());
//        }
//
//        log.info("构建透视图：获得 attrkeyList ={}", JSON.toJSON(attrkeyList));

        approvalParamList.stream().collect(Collectors.groupingBy(a -> a.get("source_display_name")))
                .forEach((k,v)->{
                    final  MapBuilder<String, Object> temp = MapBuilder.create(new HashMap<String,Object>())
                            .put("alter_type",v.get(0).get("alter_type"))
                            .put("ci_type_name",v.get(0).get("ci_type_name"))
                            .put("source_display_name",k);

                    v.forEach(a-> temp.put("old_".concat(a.get("attr_id").toString()),a.get("old_val")).put("new_".concat(a.get("attr_id").toString()),a.get("new_val")).put("record_id",a.get("record_id")) );

                    list.add(temp.build());

                });

        // 这里的record_id 是从 cmdb 获取的 ,是 数值类型， 落库云枢会转成 String,所以直接强转
        return list.stream().sorted(Comparator.comparing(a-> (Integer)a.get("record_id") )).collect(Collectors.toList());
    }




    /**
     *  流程生效后 变更信息 写入nc 同步池
     */
    @RequestMapping("approvalPassToNcSyncPool")
    public void approvalPassToNcSyncPool(String instanceId){

        WorkflowInstanceModel workflowInstance = getWorkflowInstanceFacade().getWorkflowInstance(instanceId);

        if (workflowInstance == null) {
            log.info("流程 不存在 id={}", instanceId);
            return;
        }

        if (workflowInstance.getState()!= WorkflowInstanceStatus.COMPLETED){
            log.info("流程不是完成状态 id={},当前状态={}",instanceId,workflowInstance.getState());
            return;
        }

        BizObjectCreatedModel bizObject = getBizObjectFacade().getBizObject(workflowInstance.getSchemaCode(), workflowInstance.getBizObjectId());

        try {
            String confirm =   bizObject.getString("confirm");

            if (!"Y".equals(confirm) ) {
                log.info("未确认通过");
                return;
            }

            Map<String, Object> baseMap = MapUtil.builder(new HashMap<String, Object>(16))
                    .put("from_sys", bizObject.get("from_sys"))
                    .put("ctime", bizObject.get("ctime"))
                    .put("mtime", bizObject.get("mtime"))
                    .put("creator", bizObject.get("creator"))
                    .put("from_sys_ref", bizObject.get("from_sys_ref"))
                    .put("commit_id", bizObject.get("commit_id"))
                    .put("data_status", bizObject.get("data_status"))
                    .build();


            List<Map<String,Object>> records = (List<Map<String, Object>>) bizObject.get("approval_alter_records");


            if (records == null || records.isEmpty()) {
                log.info("审批流程子表未获得数据");
                return;
            }



            List<BizObjectModel> bizList = new ArrayList<>(records.size());

            for (Map<String, Object> record : records) {
                bizList.add(new BizObjectModel(cmdb_asset_nc_sync, MapUtil.builder(new HashMap<String, Object>(32))
                        .put("record_id", record.get("id"))
                        .put("alter_type", record.get("alter_type"))
                        .put("ci_id", record.get("ci_id"))
                        .put("ci_type_id", record.get("ci_type_id"))
                        .put("ci_type_name", record.get("ci_type_name"))
                        .put("source_display_name", record.get("source_display_name"))
                        .put("attr_id", record.get("attr_id"))
                        .put("attr_name", record.get("attr_name"))
                        .put("old_val", record.get("old_val"))
                        .put("new_val", record.get("new_val"))
                        .put("createdTime",new Date())
                        .put("modifiedTime",new Date())
                        .putAll(baseMap)
                        .build(), false));
            }


            log.info("流程审批需同步数据：{},",bizList.size());

            //判断数据是否已存在nc同步池里
            BizObjectQueryModel bizObjectQueryModel = new BizObjectQueryModel();

            FilterExpression.Item filter = Q.it("record_id", FilterExpression.Op.In, bizList.stream().map(a -> a.getString("record_id")).collect(Collectors.toList()));

            bizObjectQueryModel.setSchemaCode(cmdb_asset_nc_sync);
            bizObjectQueryModel.setQueryCode(cmdb_asset_nc_sync);
            bizObjectQueryModel.setFilterExpr(filter);
            bizObjectQueryModel.setPageable(new PageableImpl(0,Integer.MAX_VALUE));

            Page<BizObjectModel> existPage = getBizObjectFacade().queryBizObjects(bizObjectQueryModel);
            log.info("nc池 已存在数据：{},",existPage.getTotal());
            if (existPage.getTotal()>0){
                List<String> existList = existPage.getContent().stream().map(a -> a.getString("record_id")).collect(Collectors.toList());
                bizList = bizList.stream().filter(a -> !existList.contains(a.getString("record_id"))).collect(Collectors.toList());
            }

            if(bizList.size()>0){
                List<String> ids = getBizObjectFacade().addBizObjects(gainAssetAdminId(), bizList, null);
                log.info("数据写入同步nc池结果：{},应写入数：{}",ids.size(),bizList.size());
            }else{
                log.info("数据写入同步nc池结果：{}",bizList.size());
            }


            //调用一次 同步nc
            toNcSync();
        } catch (Exception e) {
            log.info("数据写入同步nc池 -系统异常：{}",instanceId);
            log.info(e.getMessage(),e);
        }

    }

    /**
     *  激活同步nc
     *
     */
    @RequestMapping("toNcSync")
    public ResponseResult<Object> toNcSync(){

        log.info("激活一次nc同步");

        executorService.execute(this::ncSync);
        return ResponseResult.builder().errcode(0L).errmsg("已激活一次nc同步").build();
    }


    /**
     *  nc 同步
     */

    private void ncSync()  {

        BizObjectQueryModel bizObjectQueryModel = new BizObjectQueryModel();
        //FilterExpression.Or filter = Q.or(Q.it("syncStatus", FilterExpression.Op.Eq, "未同步"), Q.it("syncStatus", FilterExpression.Op.Eq, "失败"));

        FilterExpression.Item filter = Q.it("syncStatus", FilterExpression.Op.NotEq, "同步成功");

        bizObjectQueryModel.setSchemaCode(cmdb_asset_nc_sync);
        bizObjectQueryModel.setQueryCode(cmdb_asset_nc_sync);
        bizObjectQueryModel.setFilterExpr(filter);
        bizObjectQueryModel.setPageable(new PageableImpl(0,Integer.MAX_VALUE));

        Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(bizObjectQueryModel);

        long total = bizObjectModelPage.getTotal();

        log.info("待同步nc 数据 数量={}",total);
        if (total ==0){
            return;
        }

        //加载条件
        getFilterCondition();


        if (filterConditions.isFail()){
            log.info("nc 同步 获取条件失败,停止nc");
            return;
        }

        List<BizObjectModel> content = (List<BizObjectModel>) bizObjectModelPage.getContent();
        List<BizObjectModel> createAsset = ncSyncCreateAsset(content);
        List<BizObjectModel> assetStatus = ncSyncDeviceStatus(content);

        List<BizObjectModel> assetUpdate = ncSyncAssetUpdate(content);

        createAsset.addAll(assetStatus);
        createAsset.addAll(assetUpdate);

        // 获取nc同步成功的数据并同步到云枢的资产明细里（过滤掉数据来源是云枢的）
        final   List<BizObjectModel> assetInfo = new ArrayList<>();
        createAsset.stream().filter(a->!"云枢系统".equals(a.getString("from_sys")))
                .collect(Collectors.groupingBy(a->a.getString("source_display_name")))
                .forEach((k,v)-> assetInfo.add(assetInfoUpdateData(k,v)));

        // 同步到资产明细
        cyncAssetInfo(assetInfo);

    }

    /**
     *  nc同步成功的数据并同步到云枢的资产明细里,并记录日志
     *
     *  cmdb 创建，变更 -> 云枢，云枢记录日志（业务规则）， 不进入同步池（from_sys 是 cmdb系统）
     *
     *  云枢  创建，变更（from_sys 页面初始化时设置为""）云枢记录日志（业务规则）
     *
     *
     */
    private void cyncAssetInfo(List<BizObjectModel> assetInfo){
//        BizSchemaModel bizSchemaModel = new BizSchemaModel();
//        bizSchemaModel.setCode(asset_info);
//        bizSchemaModel.setBusinessRuleEnable(false);



        List<String> ids = getBizObjectFacade().addBizObjects(gainAssetAdminId(), assetInfo, "asset_num");

//        //构建日志数据并调用写入日志
//        assetInfo.stream().map(a -> MapBuilder.create(new HashMap<String,Object>()).put("asset_log_channel",  a.getString("asset_log_channel"))
//                .put("asset_id", a.getSequenceNo())
//                .put("asset_num", a.getString("asset_num"))
//                .put("operator", gainAssetAdminId())
//                .put("asset_detail", a.getId())
//                .put("sn", a.getString("sn"))
//                .put("brand", a.getString("brand"))
//                .put("model", a.getString("model"))
//                .put("status", a.getString("status"))
//                .put("from_sys","cmdb系统")
//                .put("station_name", a.getString("station_name")).build()).forEach(this::assetDetailLog);


        log.info("同步资产明细,应操作{}条数据,实际成功数据{}条",assetInfo.size(),ids.size());
    }



    /**
     *  资产新增
     *  操作类型是 create_attr_val，
     *  操作的属性是  资产编号（61）
     * @return
     */
    private List<BizObjectModel> ncSyncCreateAsset(List<BizObjectModel> content){
        List<BizObjectModel> list = content.stream().filter(a ->  "create_attr_val".equals(a.getString("alter_type")) && "61".equals(a.getString("attr_id"))).collect(Collectors.toList());

        if (list.isEmpty()){
            return list;
        }

        Map<String, List<Map<String, String>>> syncCreateAssetParm = MapUtil.builder("date", list.stream().map(a -> MapUtil.builder("dict", "0").put("def57", a.getString("new_val")).build()).collect(Collectors.toList())).build();
        Map<String,String> syncSuccess = new HashMap<>();
        Map<String,String> syncFail = new HashMap<>();

        try {

            if (log.isDebugEnabled()) {
                log.debug("ncSyncCreateAsset-request->{}", JSON.toJSONString(syncCreateAssetParm));
            }

            String  syncRst = HttpClientUtils.doPost( ncFaCardServlet , JSON.toJSONString(syncCreateAssetParm), ncEsbheaderMap,50000,120000,120000);

            if (StringUtils.isNotEmpty(syncRst)) {
                JSONObject rst = JSONObject.parseObject(syncRst);
                log.debug("ncSyncCreateAsset->{}",rst);
                if ("200".equals(rst.getString("code"))){
                    getNcRest(syncSuccess, syncFail, rst);
                }
            }
        } catch (Exception e) {
            log.info("ncSyncDeviceStatus nc同步方法执行失败");
            String errorMsg = "系统异常：".concat(e.getMessage());
            log.error(errorMsg,e);
            list.stream().map(a->a.getString("source_display_name")).distinct().forEach(a->syncFail.put(a,errorMsg));
        }
        updateNcSync(list, syncSuccess, syncFail);
        return list.stream().filter(a -> "同步成功".equals(a.getString("syncStatus"))).collect(Collectors.toList());
    }

    private void updateNcSync(List<BizObjectModel> list, Map<String, String> syncSuccess, Map<String, String> syncFail) {
        list.forEach(a -> {
            String assetNo = a.getString("source_display_name");
            if (syncSuccess.containsKey(assetNo)) {
                a.put("syncStatus", "同步成功");
                a.put("syncRemark", syncSuccess.get(assetNo));
            } else {
                a.put("syncStatus", "失败");
                a.put("syncRemark", syncFail.get(assetNo));
            }
            String id = a.getId();
            Date createdTime = a.getCreatedTime();
            //排除系统字段
            for (DefaultPropertyType item : DefaultPropertyType.values()) {
                a.getData().remove(item.getCode());
            }
            //补回排除的系统字段
            a.put(DefaultPropertyType.ID.getCode(), id);
            a.put("modifiedTime",new Date());
            a.put("createdTime", createdTime);
        });
        // 修改同步池里的状态
        getBizObjectFacade().addBizObjects(gainAssetAdminId(), list, null);
    }

    private void getNcRest(Map<String, String> syncSuccess, Map<String, String> syncFail, JSONObject rst) {
        List<Map<String,String>> sucess = (ArrayList<Map<String, String>>)rst.getObject("sucess", ArrayList.class);
        if (sucess.size() > 0) {
            syncSuccess.putAll(sucess.stream().collect(Collectors.toMap(a -> a.get("code"), a -> a.get("message"), (key1, key2) -> key2)));
        }
        List<Map<String, String>> faile = (ArrayList<Map<String, String>>)rst.getObject("faile", ArrayList.class);
        if (faile.size() > 0) {
            syncFail.putAll(faile.stream().collect(Collectors.toMap(a -> a.get("code"), a -> a.get("message"), (key1, key2) -> key2)));
        }
    }


    /**
     *  资产属性变更
     *  条件： 1. attr_id 不是 设备状态(62)
     *        2. attr_id 不是  资产编号（61）且 操作属性是创建  的资产变更 处理数据
     * @param content
     */
    private List<BizObjectModel> ncSyncAssetUpdate(List<BizObjectModel> content){

        // 状态
        List<BizObjectModel> list = content.stream().filter(a ->{
            // 过滤 62状态属性
            if("62".equals(a.getString("attr_id"))){
                return false;
            }
            //过滤掉 61 资产编号属性，且操作属性是创建
            return !"61".equals(a.getString("attr_id")) || !"create_attr_val".equals(a.getString("alter_type"));
        }).collect(Collectors.toList());


        if (list.isEmpty()) {
            return list;
        }

        Map<String, List<Map<String, String>>> assetUpdateParm = getAssetUpdateParm(list.stream().collect(Collectors.groupingBy(a -> a.getString("source_display_name"))));

        Map<String,String> syncSuccess = new HashMap<>();
        Map<String,String> syncFail = new HashMap<>();
        try {
            if (log.isDebugEnabled()) {
                log.debug("ncSyncAssetUpdate-request->{}",JSON.toJSONString(assetUpdateParm));
            }
            String  statusRst = HttpClientUtils.doPost( ncFaCardServlet , JSON.toJSONString(assetUpdateParm), ncEsbheaderMap,50000,120000,120000);

            if (StringUtils.isNotEmpty(statusRst)) {
                JSONObject rst = JSONObject.parseObject(statusRst);
                log.debug("ncSyncAssetUpdate->{}",rst);
                if ("200".equals(rst.getString("code"))){
                    getNcRest(syncSuccess, syncFail, rst);
                }

            }
        } catch (Exception e) {
            log.info("ncSyncDeviceStatus nc同步方法执行失败");
            String errorMsg = "系统异常：".concat(e.getMessage());
            log.error(errorMsg,e);
            list.stream().map(a->a.getString("source_display_name")).distinct().forEach(a->syncFail.put(a,errorMsg));
        }

        updateNcSync(list, syncSuccess, syncFail);
        return list.stream().filter(a -> "同步成功".equals(a.getString("syncStatus"))).collect(Collectors.toList());
    }

    //ncEsb请求头
    final static Map<String, String> ncEsbheaderMap = MapBuilder.create(new HashMap<String, String>())
            .put("Content-Type", "application/json; charset=utf-8")
            .put("ClientId", "com.primeton.esb.consumer.cloudpivot")
            .put("OperationCode", "com.primeton.esb.producer.nc.prodsupply.faCard")
            .put("Timestamp", String.valueOf(System.currentTimeMillis()))
            .put("Authorization", "Basic ".concat((new sun.misc.BASE64Encoder()).encode(("administrator:P@ssword01").getBytes())))
            .build();


    /**
     *
     *  设备状态 修改
     *  条件： attr_id  62（状态）
     *  source_display_name 资产编号, new_val变动的新值
     */
    private List<BizObjectModel>  ncSyncDeviceStatus (List<BizObjectModel> content){
        List<BizObjectModel> list = content.stream().filter(a -> "62".equals(a.getString("attr_id"))).collect(Collectors.toList());

        if (list.isEmpty()) {
            return list;
        }

        Map<String, List<Map<String, String>>> deviceStatusParam = MapUtil.builder("date", list.stream().map(a ->
                MapUtil.builder(new HashMap<String, String>(16))
                        .put("dict", "2")
                        .put("def57_before", a.getString("source_display_name"))
                        .put("pk_usingstatus_after", a.getString("new_val")).build() ).collect(Collectors.toList())).build();
        Map<String,String> syncSuccess = new HashMap<>();
        Map<String,String> syncFail = new HashMap<>();
        try {
            if (log.isDebugEnabled()) {
                log.debug("ncSyncDeviceStatus-request->{}", JSON.toJSONString(deviceStatusParam));
            }
            String statusRst = HttpClientUtils.doPost( ncFaCardServlet , JSON.toJSONString(deviceStatusParam), ncEsbheaderMap,50000,120000,120000);

            if (StringUtils.isNotEmpty(statusRst)) {
                JSONObject rst = JSONObject.parseObject(statusRst);
                log.debug("ncSyncDeviceStatus->{}",rst);
                if ("200".equals(rst.getString("code"))){
                    getNcRest(syncSuccess, syncFail, rst);
                }

            }

        } catch (Exception e) {
            log.info("ncSyncDeviceStatus nc同步方法执行失败");
            String errorMsg = "系统异常：".concat(e.getMessage());
            log.error(errorMsg,e);
            list.stream().map(a->a.getString("source_display_name")).distinct().forEach(a->syncFail.put(a,errorMsg));
        }

        updateNcSync(list, syncSuccess, syncFail);

        return  list.stream().filter(a -> "同步成功".equals(a.getString("syncStatus"))).collect(Collectors.toList());
    }

    /**
     *  生成 assetInfo 数据  asset_info ，nc 同步成功后，写入云枢资产明细表
     */
    private BizObjectModel assetInfoUpdateData(String asset_num,List<BizObjectModel> ncSyncSuccessList ){

        //判断资产编号是否存在
        BizObjectQueryModel queryModel = new BizObjectQueryModel();
        queryModel.setFilterExpr(Q.it("asset_num", FilterExpression.Op.Eq,asset_num));
        queryModel.setSchemaCode(asset_info);
        queryModel.setQueryCode(asset_info);
        queryModel.setPageable(new PageableImpl(0,10));
        Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);

        BizObjectModel assetInfo ;


        if (bizObjectModelPage.getTotal()>0){
            assetInfo = bizObjectModelPage.getContent().get(0);
            assetInfo.put("asset_log_channel","CMDB-变更");
        }else{ // 云枢资产明细里没有，此资产，创建
            assetInfo = new BizObjectModel();
            assetInfo.setSchemaCode(asset_info);
            assetInfo.setCreater(gainAssetAdminId());
            assetInfo.setSequenceStatus(SequenceStatus.COMPLETED.toString());

            assetInfo.put("asset_num",asset_num);
            assetInfo.put("asset_log_channel","CMDB-新增");

            //判断品牌的千寻的是自研，默认购买
            assetInfo.put("assets_sources","购买");
            String rst = HttpClientUtils.doGet(cmdbHost.concat(cmdbBaseDeviceInfo.concat(asset_num)));
            if (StringUtils.isNotEmpty(rst)){
                JSONObject rstJson = JSON.parseObject(rst);
                if ("1000".equals(rstJson.getString("code"))){
                    JSONArray jsonArray = rstJson.getJSONArray("data");
                    JSONObject data;
                    if (jsonArray != null && jsonArray.size()>0 && (data = jsonArray.getJSONObject(0)) !=null ){
                        if ("千寻".equals(data.getString("Brand"))){
                            assetInfo.put("assets_sources","自建");
                        }
                    }
                }
            }
            //设置管理和使用部门
            if (!filterConditions.getAssetCmdb2ysDept().isEmpty()){
                SelectionValue[] d;
                for (Map.Entry<String,String> entry : filterConditions.getAssetCmdb2ysDept().entrySet()){
                    d = new SelectionValue[]{new SelectionValue()};
                    d[0].setId( entry.getValue());
                    d[0].setType(UnitType.DEPARTMENT);
                    assetInfo.put(entry.getKey(),d);
                }
            }

            //小类，中类，大类 直接查询
            if (ncSyncSuccessList.size() > 0) {
                String ciTypeName = ncSyncSuccessList.get(0).getString("ci_type_name");
                queryModel = new BizObjectQueryModel();

                queryModel.setFilterExpr(Q.and(new ArrayList<FilterExpression>() {{
                    add(Q.it("asset_cmdb2nc_status", FilterExpression.Op.Eq, "是"));
                    add(Q.it("asset_division", FilterExpression.Op.Eq, ciTypeName));
                }}));
                queryModel.setSchemaCode("asset_CMDBtoNC_type");
                queryModel.setQueryCode("asset_CMDBtoNC_type");
                queryModel.setPageable(new PageableImpl(0,Integer.MAX_VALUE));

                bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);

                if (bizObjectModelPage.getContent() != null){
                    assetInfo.put("asset_division", bizObjectModelPage.getContent().get(0).get("asset_division"));
                    assetInfo.put("asset_section", bizObjectModelPage.getContent().get(0).get("asset_section"));
                    assetInfo.put("asset_class", bizObjectModelPage.getContent().get(0).get("asset_class"));
                }
            }

        }

        assetInfo.put("from_sys","cmdb系统");

        //给资产明细对象赋值
        ncSyncSuccessList.forEach(a->{
                    String attr_id = a.getString("attr_id");
                    if (filterConditions.getAttributeMapping().containsKey(attr_id) ){
                        String ysKey = filterConditions.getYsKey(attr_id);
                        if (StringUtils.isNotEmpty(ysKey)){
                            assetInfo.put(ysKey,a.getString("new_val"));
                        }
                    }
                }
        );

        return assetInfo;
    }






    final static Map<String, String> assetNcPara = MapUtil.builder("dict", "1").put("card_model_after", "")
            .put("def57_before", "").put("def57_after", "")
            .put("def65_after", "").put("def66_after", "")
            .put("asset_code_after", "").put("def71_after", "").put("pk_jobmngfil_after","")
            .put("def3_after", "").put("remark", "").build();

    /**
     *  组合资产变更nc 同步请求对象 ，
     *
     * @param assetUpdateMap
     * @return
     */
    public Map<String, List<Map<String, String>>> getAssetUpdateParm(Map<String, List<BizObjectModel>> assetUpdateMap){
        List<Map<String, String>> list = new ArrayList<>();
        assetUpdateMap.forEach((k,v)->{
            final   Map<String, String> parm = MapUtil.builder(new HashMap<String,String>()).putAll(assetNcPara).put("def57_before",k).build();
            v.forEach(a->{
                String attr_id = a.getString("attr_id");
                if (filterConditions.getAttributeMapping().containsKey(attr_id)){
                    String ncKey = filterConditions.getNcKey(attr_id);
                    if (StringUtils.isNotEmpty(ncKey)){
                        parm.put(ncKey,a.getString("new_val"));
                    }
                }
            });

            list.add(parm);
        });
        return MapUtil.builder("date", list).build();
    }




    /**
     *  根据资产编码查询资产原值和净值
     * @return
     */
    @RequestMapping("queryAssetValue")
    public JSONObject queryAssetValue(String code){

        JSONObject rest = new JSONObject() {{
            put("localoriginvalue",0);
            put("netvalue",0);
            put("code","");
        }};


        if (StringUtils.isEmpty(code)){
            log.info("资产编码 code 为空");
            return rest;
        }

        HashMap<String, Object> param = new HashMap<String, Object>() {{
            put("date", new ArrayList<Map<String, String>>() {{
                add(new HashMap<String, String>() {{
                    put("dict", "3");
                    put("def57", code);
                }});
            }});
        }};

        try {
            String s = HttpClientUtils.doPost( ncFaCardServlet , JSON.toJSONString(param), ncEsbheaderMap);

            //返回结果： {"message":"接收成功","sucess":[{"localoriginvalue":10000,"netvalue":10000,"code":"100868"}],"faile":[],"code":"200"} ,又改了

            if (StringUtils.isNotEmpty(s)) {

                JSONObject rst = JSONObject.parseObject(s);
                if ("200".equals(rst.getString("code"))){

                    JSONArray sucess = rst.getJSONArray("sucess");

                    if (sucess.size()>0){
                        JSONObject o = sucess.getJSONObject(0);
                        rest.put("localoriginvalue", o.get("localoriginvalue"));
                        rest.put("netvalue", o.get("netvalue"));
                        rest.put("code", o.get("code"));

                    }
                }

            }

        } catch (Exception e) {
            log.info(" 根据资产编码查询资产原值和净值系统异常:{}",e.getMessage());
        }

        return rest;
    }




    /**
     * 资产明细 修改记录日志
     * 云枢系统-删除
     * 云枢系统-编辑更新
     * 云枢系统-新增
     * @param map
     * @return
     */
    @PostMapping("assetDetailLog")
    public Object assetDetailLog(@RequestBody Map<String,Object> map){
        log.info("开始资产明显变更逻辑");

        String objId = (String) map.get("asset_detail");
        String from_sys = (String) map.get("from_sys");

        String operator;
        String asset_log_channel = (String) map.get("asset_log_channel");

        BizObjectModel biz = new BizObjectModel();

        biz.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        biz.setSchemaCode("asset_detail_log");
        biz.setCreatedTime(new Date());
        biz.setSequenceStatus(SequenceStatus.COMPLETED.toString());
        String asset_num = (String) map.get("asset_num");
        biz.getId();

        biz.put("asset_id",map.get("asset_id"));
        biz.put("asset_num",asset_num);

        //资产明细
        BizObjectCreatedModel bizObject = null;

        if (!"云枢系统-删除".equals(asset_log_channel)){
            operator = (String) map.get("operator");

            Object sn = Optional.ofNullable(map.get("sn")).orElse("").toString();
            Object brand =  Optional.ofNullable(map.get("brand")).orElse("").toString();
            Object model =  Optional.ofNullable(map.get("model")).orElse("").toString();
            Object status = Optional.ofNullable(map.get("status")).orElse("").toString();
            Object station_name =  Optional.ofNullable(map.get("station_name")).orElse("").toString();

            if ("云枢系统-编辑更新".equals(asset_log_channel)){
                bizObject = getBizObjectFacade().getBizObject("asset_info", objId);

                if (bizObject != null){
                    if (sn.equals(bizObject.get("sn"))  && brand.equals(bizObject.get("brand")) && model.equals(bizObject.get("model"))
                            && status.equals(bizObject.get("status")) && station_name.equals(bizObject.get("station_name"))  && asset_num.equals(bizObject.get("asset_num"))){

                        log.info("资产明细无关机字段修改");

                        return getOkResponseResult("资产明细无关机字段修改");
                    }
                }else{
                    log.info("资产明细编辑更新,明细不存在");
                    return getOkResponseResult("资产明细编辑更新,明细不存在");
                }

            }
            biz.put("sn",sn);
            biz.put("brand",brand);
            biz.put("model",model);
            biz.put("status",status);
            biz.put("station_name",station_name);
            biz.put("asset_log_channel",asset_log_channel);

        }else {

            ArrayList<Map<String,Object>> creater1 = (ArrayList<Map<String, Object>>) map.get("operator");
            if (creater1 != null && creater1.size()>0){
                operator = (String) creater1.get(0).get("id");
            }else{
                operator = "admin";
            }

        }
        biz.setCreater(operator);


        if ("cmdb系统".equals(from_sys)){
            asset_log_channel = asset_log_channel.replaceAll("云枢系统",from_sys);
        }
        biz.put("asset_log_channel",asset_log_channel);

        biz.put("asset_detail",objId);

        String saveId = getBizObjectFacade().saveBizObject(operator, biz, false);

        biz.put("asset_log_channel",asset_log_channel);

        //云枢操作的需要写到nc 同步池中, cmdb系统来的日志信息不需要进入同步池
        if (!"cmdb系统".equals(from_sys) && StringUtils.isNotEmpty(asset_num) &&  asset_log_channel.startsWith("云枢系统") && !"云枢系统-删除".equals(asset_log_channel)){
            if (saveId != null) {
                BizObjectCreatedModel assetlog = getBizObjectFacade().getBizObject("asset_detail_log", saveId);
                if (assetlog != null){
                    biz.setSequenceNo(assetlog.getSequenceNo());
                }
            }

            if (bizObject != null && StringUtils.isEmpty(bizObject.getString("asset_num"))) {
                //如果资产明细修改时，资产编码旧值 为空，写入nc同步池里，默认此操作为新增
                biz.put("asset_log_channel","云枢系统-新增");

            }
            yunshuOperationToNc(biz,bizObject);
        }



        return getOkResponseResult("成功");
    }



    /**
     *  云枢资产明细 新增及修改需要同步到nc
     * @param biz
     * @param oldBiz
     */
    private void yunshuOperationToNc(BizObjectModel biz,BizObjectCreatedModel oldBiz){
        String commit_id = UUID.randomUUID().toString().replace("-", "");
        String operator = biz.getString("creater");

        if (StringUtils.isNotEmpty(operator)){
            UserModel user = getOrganizationFacade().getUser(operator);
            if (user != null){
                operator = user.getName();
            }
        }


        //6个字段要构建6条nc 同步池的行数据， 新增时值为空就不用构建，变更时 新增值与旧相同也不用构建
        Map<String, Map<String, String>> attrMap = getAttr();

        String alter_type = "云枢系统-编辑更新".equals(biz.getString("asset_log_channel")) ?"modify_attr_val":"create_attr_val";

        String source_display_name = biz.getString("asset_num");

        if (oldBiz != null && !source_display_name.equals(oldBiz.getString("asset_num"))){
            source_display_name = oldBiz.getString("asset_num");
        }

        //nc 同步池数据模板
        Map<String, Object> temp = new MapBuilder<String, Object>(new HashMap<>())
                .put("from_sys", "云枢系统")
                .put("ctime", new Date())
                .put("creator", operator)
                .put("from_sys_ref", biz.getString("asset_id"))
                .put("commit_id", commit_id)
                .put("data_status", "confirmed")
                .put("alter_type", alter_type)
                .put("ci_id", biz.getString("asset_id"))
                .put("source_display_name", source_display_name)
                .put("ci_type_id", "")
                .put("ci_type_name", "")
                .put("createdTime",new Date())
                .put("modifiedTime",new Date())
                .build();


        List<BizObjectModel> list = new ArrayList<>();

        //循环比较再赋值
        int i =1;



        for (Map.Entry<String,Map<String,String>> entry : attrMap.entrySet()) {
            //新值
            String new_val = biz.getString(entry.getKey());
            String old_val ="";
            if (StringUtils.isNotEmpty(new_val) &&  (oldBiz ==null || !new_val.equals(old_val = oldBiz.getString(entry.getKey())))){
                list.add(new BizObjectModel("cmdb_asset_nc_sync",
                        new MapBuilder<String, Object>(new HashMap<>()).put("attr_id", entry.getValue().get(AssetDictionary.assetDictKey))
                                .put("attr_name", entry.getValue().get(AssetDictionary.assetDictValue)).putAll(temp)
                                .put("old_val", old_val).put("new_val", new_val).put("ci_type_name",entry.getValue().get("asset_division"))
                                .put("ci_id",biz.getString("asset_id"))
                                .put("record_id",biz.getSequenceNo().concat("_").concat(String.valueOf(i++)))
                                .build()
                        , false));
            }

        }


        int success = 0;
        log.info("云枢资产明细变动写入nc 池中,应写入{}",list.size());
        if (!list.isEmpty()) {
            List<String> list1 = getBizObjectFacade().addBizObjects(gainAssetAdminId(), list, null);
            success = list1.size();
        }
        log.info("云枢资产明细变动写入nc 池中,实际写入{}",success);


    }

    /**
     *  获取资产明细到nc池属性映射
     * @return
     */
    private  Map<String, Map<String, String>> getAttr(){

        getFilterCondition();

        final Map<String, Map<String, String>> map = new HashMap<>();

        if (filterConditions.isFail()) {
            String sss = "{\"asset_num\":{\"asset_dict_key\":\"61\",\"asset_dict_value\":\"资产编号\"},\n" +
                    "\"sn\":{\"asset_dict_key\":\"60\",\"asset_dict_value\":\"SN\"},\n" +
                    "\"brand\":{\"asset_dict_key\":\"58\",\"asset_dict_value\":\"品牌\"},\n" +
                    "\"model\":{\"asset_dict_key\":\"59\",\"asset_dict_value\":\"型号\"},\n" +
                    "\"status\":{\"asset_dict_key\":\"62\",\"asset_dict_value\":\"设备状态\"},\n" +
                    "\"station_name\":{\"asset_dict_key\":\"2\",\"asset_dict_value\":\"站点名称\"}}";

            map.putAll(JSONObject.parseObject(sss,map.getClass()));

        }else{
            Map<String, Map<String, String>> am = filterConditions.getAttributeMapping();

            am.forEach((k,v)-> map.put(v.get(AssetDictionary.toYs),v));

        }

        return map;

    }


    /**
     *  设置配置信息
     * @param map
     */
    @RequestMapping("/setAssetAdminInfo")
    public void setAssetAdminInfo(@RequestBody Map<String,Object> map){


            String approvalUserId =  Optional.ofNullable((ArrayList<Map<String,String>>)map.get("approvalUserId")).orElse(new ArrayList<>(0)).stream().findFirst().orElse(new HashMap<>()).get("id");
            String assetAdminId = Optional.ofNullable((ArrayList<Map<String,String>>)map.get("assetAdminId")).orElse(new ArrayList<>(0)).stream().findFirst().orElse(new HashMap<>()).get("id");
            log.info("资产运维信息变更，approvalUserId={}，assetAdminId={}",approvalUserId,assetAdminId);

            BoundHashOperations hash = redisTemplate.boundHashOps("assetAdminInfo");

            if (StringUtils.isNotEmpty(approvalUserId)){

                UserModel user = getOrganizationFacade().getUser(approvalUserId);

                if (user != null &&  StringUtils.isNotEmpty(user.getUsername()) ){
                    hash.put("approvalUserCode",user.getUsername());

                    log.info("approvalUserCode 流程发起人修改成={}", user.getUsername());
                }else{
                    log.info("approvalUserCode 流程发起人修改失败，人员不存在");
                }


            }

            if (StringUtils.isNotEmpty(assetAdminId)){
                UserModel user = getOrganizationFacade().getUser(assetAdminId);

                if (user != null) {
                    hash.put("assetAdminId",user.getId());
                    log.info("assetAdminId 日志默认创建人修改成={}",user.getId());
                }else{
                    log.info("assetAdminId 日志默认创建人修改失败，人员不存在");
                }

            }

    }


    private String gainAssetAdminId(){ return getSetting("assetAdminId");}
    private String gainApprovalUserCode(){ return getSetting("approvalUserCode");}

    /**
     * 获取资产运维配置
     *  资产日志 创建人的 id : assetAdminId
     *  资产审批发起的 code : approvalUserCode
     */
    private String getSetting(String key){

        if (!StringUtils.equalsAny(key,"assetAdminId","approvalUserCode")){
            return null;
        }

        BoundHashOperations hash = redisTemplate.boundHashOps("assetAdminInfo");

        String val = (String) hash.get(key);

        if (StringUtils.isEmpty(val)){

            BizObjectQueryModel queryModel = new BizObjectQueryModel();
            queryModel.setSchemaCode("setAssetAdminInfo");
            queryModel.setQueryCode("setAssetAdminInfo");
            queryModel.setPageable(new PageableImpl(0,10));
            Page<BizObjectModel> bizObjectModelPage = getBizObjectFacade().queryBizObjects(queryModel);

            if (bizObjectModelPage.getTotal()>0){
                BizObjectModel bizObjectModel = bizObjectModelPage.getContent().get(0);
                String assetAdminId = Optional.ofNullable((ArrayList<SelectionValue>) bizObjectModel.get("assetAdmin"))
                        .orElse(new ArrayList<>(0)).stream().findFirst().orElse(new SelectionValue()).getId();

                String approvalUserCode = Optional.ofNullable((ArrayList<SelectionValue>) bizObjectModel.get("approvalUser"))
                        .orElse(new ArrayList<>(0)).stream().findFirst().orElse(new SelectionValue()).getId();


                if (StringUtils.isNotEmpty(assetAdminId)){
                    UserModel user = getOrganizationFacade().getUser(assetAdminId);

                    if (user != null){
                        assetAdminId = user.getId();
                        log.info("assetAdminId 日志默认创建人修改成={}",assetAdminId);
                    }else{
                        log.info("assetAdminId 日志默认创建人修改失败，人员不存在,使用默认值");
                        assetAdminId = this.assetAdminId;
                    }
                }else{
                    log.info("assetAdminId 流程发起人修改失败，人员不存在,使用默认值");
                    assetAdminId = this.assetAdminId;
                }


                if (StringUtils.isNotEmpty(approvalUserCode)){
                    UserModel user = getOrganizationFacade().getUser(approvalUserCode);

                    if (user != null){

                        approvalUserCode = user.getUsername();
                        log.info("approvalUserCode 流程发起人修改成={}",approvalUserCode);
                    }else{
                        approvalUserCode = this.approvalUserCode;
                        log.info("approvalUserCode 流程发起人修改失败，人员不存在");
                    }
                }else{
                    approvalUserCode = this.approvalUserCode;
                    log.info("approvalUserCode 流程发起人修改失败，人员不存在");
                }

                Map<String, String> put = MapBuilder.create(new HashMap<String, String>()).put("approvalUserCode", approvalUserCode).put("assetAdminId", assetAdminId).build();

                hash.putAll(put);


               val = put.get(key);

            }

        }


        return val;
    }


}




